package longin

import (
	"fmt"
	//"log"
	"net/http"
	"project3/model"
	"project3/mysql"
	"time"

	//"github.com/casbin/casbin/v2"
	//gormadapter "github.com/casbin/gorm-adapter/v3"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"
)

var jwtSecret = []byte("wangyachuan")

//var enforcer *casbin.Enforcer

// Register 是一个处理用户注册请求的HTTP处理函数
func Register(ctx *gin.Context) {
	// 获取数据库连接
	db := mysql.GetDB()
	if db == nil {
		// 如果数据库连接为空，则返回500内部服务器错误
		ctx.JSON(500, gin.H{
			"code":    500,
			"message": "数据库连接失败",
		})
		return
	}

	// 绑定请求体中的JSON数据到requestUser变量
	var requestUser model.User
	if err := ctx.Bind(&requestUser); err != nil {
		// 如果绑定失败，则返回422无法处理的实体错误
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    422,
			"message": "参数绑定失败: " + err.Error(),
		})
		return
	}

	// 从requestUser中提取用户名、手机号和密码
	name := requestUser.Name
	telephone := requestUser.Telephone
	password := requestUser.Password

	// 验证输入数据的合法性
	if len(name) == 0 {
		// 如果用户名为空，则返回422无法处理的实体错误
		ctx.JSON(422, gin.H{
			"code":    422,
			"message": "用户名不能为空",
		})
		return
	}

	if len(telephone) != 11 {
		// 如果手机号长度不为11位，则返回422无法处理的实体错误
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    422,
			"message": "手机号必须为11位",
		})
		return
	}

	if len(password) < 6 {
		// 如果密码长度少于6位，则返回422无法处理的实体错误
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    422,
			"message": "密码不能少于6位",
		})
		return
	}

	// 检查手机号是否已存在
	var user model.User
	db.Where("telephone = ?", telephone).First(&user)
	if user.ID != 0 {
		// 如果手机号已存在，则返回422无法处理的实体错误
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    422,
			"message": "用户已存在",
		})
		return
	}

	// 对密码进行加密处理
	hasedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		// 如果密码加密失败，则返回500内部服务器错误
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    500,
			"message": "密码加密错误",
		})
		return
	}

	// 创建新用户
	newUser := model.User{
		Name:      name,
		Telephone: telephone,
		Password:  string(hasedPassword),
	}
	db.Create(&newUser)

	// 注册成功，返回200成功状态码和成功消息
	ctx.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "注册成功",
	})
}

func Login(ctx *gin.Context) {
	// 获取数据库连接
	db := mysql.GetDB()

	// 获取参数
	// 此处使用Bind()函数，可以处理不同格式（JSON、XML等）的前端数据，并自动绑定到结构体变量中
	var requestUser model.User
	if err := ctx.Bind(&requestUser); err != nil {

		return
	}

	telephone := requestUser.Telephone
	password := requestUser.Password

	// 数据验证
	// 验证手机号长度是否为11位
	if len(telephone) != 11 {
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    422,
			"message": "手机号必须为11位",
		})
		return
	}

	// 验证密码长度是否不少于6位
	if len(password) < 6 {
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    422,
			"message": "密码不能少于6位",
		})
		return
	}

	// 判断手机号是否存在
	var user model.User
	db.Where("telephone = ?", telephone).First(&user)
	if user.ID == 0 {
		// 如果用户ID为0，表示没有找到对应的用户
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    422,
			"message": "用户不存在",
		})
		return
	}

	// 判断密码是否正确
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
		// 如果密码比对失败，返回错误信息
		ctx.JSON(http.StatusUnprocessableEntity, gin.H{
			"code":    422,
			"message": "密码错误",
		})
		return
	}

	// 创建一个JWT Claims
	claims := &jwt.RegisteredClaims{
		ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)), // 设置过期时间为24小时后
		Issuer:    "wangyachaun",                                      // 使用您的应用名称或域名作为发行人
		Subject:   fmt.Sprintf("%d", user.ID),
	}

	// 创建一个新的Token，使用HS256算法并设置密钥
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 签署Token
	tokenString, err := token.SignedString(jwtSecret)
	if err != nil {
		// 如果签署失败，返回服务器错误
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "服务器内部错误",
		})
		return
	}

	ctx.Header("Authorization", tokenString)

	// 验证成功，返回登录成功的结果给前端，包括JWT令牌
	ctx.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "登录成功",
		"token":   tokenString, // 返回JWT令牌
	})
}

// CustomClaims 是一个自定义的JWT声明结构体，它嵌入了jwt.RegisteredClaims结构体
// 并添加了UID和Username两个字段，用于存储用户相关的额外信息
type CustomClaims struct {
	jwt.RegisteredClaims        // 嵌入jwt.RegisteredClaims，获得标准的JWT声明字段
	Telephone            uint   `json:"Telephone"` // 用户的唯一ID
	Name                 string `json:"Name"`      // 用户名

}

// ParseAndVerifyJWT 函数用于解析并验证JWT令牌
// 参数tokenString是待解析的JWT字符串
// 返回值是一个指向CustomClaims的指针和一个error，如果解析或验证失败，error不为nil
func ParseAndVerifyJWT(tokenString string) (*CustomClaims, error) {
	// 使用jwt.ParseWithClaims函数解析JWT，并传入CustomClaims作为预期的声明类型
	// 第二个参数是一个函数，用于提供密钥来验证JWT的签名
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 这里直接返回了jwtSecret作为密钥，jwtSecret是一个在程序其他地方定义的变量
		// 假设jwtSecret是一个有效的密钥，用于验证JWT的签名
		return jwtSecret, nil
	})

	if err != nil {
		// 如果解析失败，返回nil和错误
		return nil, err
	}

	// 检查token的Claims是否可以被转换为*CustomClaims，并且token是否有效
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		// 如果转换成功且token有效，返回claims和nil
		return claims, nil
	}

	// 如果以上条件都不满足，返回nil和一个表示"无效token"的错误
	return nil, fmt.Errorf("无效 token")
}

// AuthMiddleware 函数返回一个gin框架的中间件函数
// 这个中间件用于验证请求的JWT令牌
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 从请求头中获取Authorization字段的值
		tokenString := c.GetHeader("Authorization")

		// 如果存在并且以"Bearer "开头，则截取"Bearer "之后的部分作为JWT令牌
		if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
			tokenString = tokenString[7:]
		} else {
			// 如果不是以"Bearer "开头或者长度不够，则将tokenString置为空字符串
			tokenString = " "
		}

		// 打印当前的token字符串，用于调试
		fmt.Println(tokenString, "当前token")

		// 如果token字符串为空，则返回未经授权的响应并终止请求
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code":    1005,
				"message": "必须传递token",
			})
			c.Abort() // 终止请求
			return
		}

		// 调用ParseAndVerifyJWT函数解析并验证JWT令牌
		claims, err := ParseAndVerifyJWT(tokenString)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code":    1005,
				"message": "token解析错误",
			})
			c.Abort() // 终止请求
			return
		}

		// 将解析出的用户ID和用户名存储到gin.Context中，供后续处理使用
		c.Set("Telephone", claims.Telephone)
		c.Set("Name", claims.Name)

		// 继续处理请求
		c.Next()
	}
}

// // CustomClaims 自定义Claims结构体
// type CustomClaims struct {
// 	jwt.RegisteredClaims
// 	UID      uint   `json:"uid"`
// 	Username string `json:"username"`
// }

// // ParseAndVerifyJWT 解析和验证JWT并返回CustomClaims
// func ParseAndVerifyJWT(tokenString string) (*CustomClaims, error) {
// 	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
// 		return jwtSecret, nil
// 	})
// 	if err != nil {
// 		return nil, err
// 	}

// 	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
// 		return claims, nil
// 	}
// 	return nil, fmt.Errorf("无效 token")
// }

// // AuthMiddleware 是一个中间件函数，用于验证JWT令牌
// func AuthMiddleware() gin.HandlerFunc {
// 	return func(c *gin.Context) {
// 		// 从请求头中获取token
// 		//WT令牌被放置在HTTP请求的Authorization头部的Bearer后面
// 		tokenString := c.GetHeader("Authorization")

// 		// 检查是否存在Authorization头部，并且它是否以"Bearer "为前缀
// 		if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
// 			// 去掉"Bearer "前缀，获取实际的JWT令牌字符串
// 			tokenString = tokenString[7:]
// 		} else {
// 			// 如果没有Authorization头部或者不是以"Bearer "为前缀，则假设没有传递token
// 			tokenString = ""
// 		}
// 		fmt.Println(tokenString, "当前token") // 打印token字符串，用于调试

// 		// 如果token为空，则响应错误消息并终止请求
// 		if tokenString == "" {
// 			c.JSON(http.StatusUnauthorized, gin.H{
// 				"code":    1005,
// 				"message": "必须传递token", // 错误码1005表示缺少token
// 			})
// 			c.Abort() // 终止请求处理流程
// 			return
// 		}

// 		// 调用ParseAndVerifyJWT函数来解析和验证JWT令牌
// 		claims, err := ParseAndVerifyJWT(tokenString)
// 		if err != nil {
// 			// 如果解析或验证过程中发生错误，则响应错误消息并终止请求
// 			c.JSON(http.StatusUnauthorized, gin.H{
// 				"code":    1005,
// 				"message": "token解析错误",
// 			})
// 			c.Abort() // 终止请求处理流程
// 			return
// 		}

// 		// 如果token验证成功，从token中解析出来的数据挂载到gin的上下文中
// 		// 这样，在后续的控制器中，可以通过c.Get()方法方便地获取这些数据
// 		c.Set("userId", claims.UID)        // 设置用户ID到上下文中
// 		c.Set("userName", claims.Username) // 设置用户名到上下文中

// 		// 继续处理请求，调用后续的处理函数
// 		c.Next()
// 	}
// }

// func parseAndVerifyJWT(tokenString string) (int, error) {
// 	token, err := jwt.ParseWithClaims(tokenString, &jwt.RegisteredClaims{}, func(token *jwt.Token) (interface{}, error) {
// 		return jwtSecret, nil
// 	})
// 	if err != nil {
// 		return 0, err
// 	}
// 	if claims, ok := token.Claims.(*jwt.RegisteredClaims); ok && token.Valid {
// 		userID, err := strconv.Atoi(claims.Subject)
// 		if err != nil {
// 			return 0, err
// 		}
// 		return userID, nil
// 	}
// 	return 0, fmt.Errorf("无效 token")
// }

// protectedRoute 是一个中间件函数，用于检查请求是否包含有效的JWT令牌，并验证用户是否有权访问特定资源
// func protectedRoute(c *gin.Context) {
// 	// 从请求头中获取JWT令牌
// 	// 通常，JWT令牌会作为"Authorization"头的一部分发送，并带有"Bearer "前缀
// 	tokenString := c.GetHeader("Authorization")
// 	if tokenString == "" {
// 		// 如果没有提供"Authorization"头或令牌为空，返回401 Unauthorized错误
// 		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "未提供Authorization头或Token为空"})
// 		return
// 	}

// 	// 验证JWT并提取用户ID
// 	userID, err := ParseAndVerifyJWT(tokenString)
// 	if err != nil {
// 		// 如果JWT验证失败，返回401 Unauthorized错误
// 		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Token验证失败"})
// 		return
// 	}

// 	// 使用Casbin进行权限检查
// 	// 这里我们假设要检查的是对"data1"资源的"read"权限
// 	object := "data1"
// 	action := "read"
// 	// Enforce方法检查用户是否有权执行特定操作（action）在特定对象（object）上
// 	// 这里使用fmt.Sprintf来格式化用户ID为"user:xxx"的形式，这是Casbin模型中的常见主体格式
// 	effect, err := enforcer.Enforce(fmt.Sprintf("user:%d", userID), object, action)
// 	if err != nil {
// 		// 如果Casbin执行过程中出现错误，返回500 Internal Server Error错误
// 		c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": "内部错误"})
// 		return
// 	}

// 	// 如果Casbin返回false，表示用户没有权限访问该资源
// 	if !effect {
// 		// 如果没有权限，返回403 Forbidden错误
// 		c.JSON(http.StatusForbidden, gin.H{"code": 403, "msg": "禁止访问"})
// 		return
// 	}

// 	// 如果用户有权限
// 	c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "成功获取数据"})
// }

// // initEnforcer 初始化Casbin的Enforcer，用于权限验证
// func initEnforcer() {
// 	// 使用gormadapter从MySQL数据库中加载策略
// 	adapter, err := gormadapter.NewAdapter("mysql", "root:root@tcp(127.0.0.1:3306)/students?charset=utf8mb4&parseTime=True&loc=Local", true)
// 	if err != nil {
// 		// 如果创建适配器失败，则记录错误并终止程序
// 		log.Fatalf("创建适配器失败: %v", err)
// 	}

// 	// 加载Casbin模型配置文件和策略数据库适配器来创建Enforcer
// 	casbin.NewEnforcer("casbintext/model.conf", adapter)
// 	if err != nil {
// 		// 如果创建Enforcer失败，则记录错误并终止程序
// 		log.Fatalf("创建执行器失败: %v", err)
// 	}

// }

// // enforce 使用已初始化的Enforcer进行权限校验
// func enforce(sub string, obj string, act string) (bool, error) {
// 	// 使用全局变量enforcer的Enforce方法进行权限校验
// 	ok, err := enforcer.Enforce(sub, obj, act)
// 	if err != nil {
// 		// 如果Enforcer执行出错，则返回错误
// 		return false, fmt.Errorf("执行权限校验时出错: %w", err)
// 	}
// 	return ok, nil
// }
